package com.dh.edu.gateway.rule;

import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.google.common.base.Optional;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ZoneAvoidanceRule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 灰度
 *
 * @Date Created in 2022/8/16 14:10
 */
@Component
public class GrayRule extends ZoneAvoidanceRule {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    public Server choose(ILoadBalancer ib, Object key) {
        Server server = null;
        // 根据当前线程获取参数（这个参数可以在拦截器中设置进去）
        Map<String, String> map = RibbonParaContext.get();
        Object grayRule = stringRedisTemplate.opsForHash().get("gray_rule", map.get("userId"));
        // 获取所有可达的服务
        List<Server> reachableServers = ib.getReachableServers();
        for (Server ser : reachableServers) {
            String gray = ((NacosServer) ser).getMetadata().get("gray");
            if (!StringUtils.isEmpty(gray) && gray.equals(grayRule)){
                server = ser;
            }
        }
        // 走默认规则
        if (null == server) {
            ILoadBalancer lb = getLoadBalancer();
            List<Server> allServers = lb.getAllServers();

            // 排除掉我们的灰度服务
            List<Server> okServers = new ArrayList<>();
            for (Server sv : allServers) {
                String gray = ((NacosServer)sv).getMetadata().get("gray");
                boolean isAdd = true;
                if (!StringUtils.isEmpty(gray)) {
                    List<Object> grayRules = stringRedisTemplate.opsForHash().values("gray_rule");
                    for (Object obj : grayRules) {
                        if (!StringUtils.isEmpty(obj) && gray.equals(obj)) {
                            isAdd = false;
                            break;
                        }
                    }
                }
                if (isAdd) {
                    okServers.add(sv);
                }
            }
            return this.getPredicate().chooseRoundRobinAfterFiltering(okServers, key).or((Server) null);
        }
        return server;
    }
}
